package com.goldsprite.projecttemplategenerator;

import com.badlogic.gdx.Application;
import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.scenes.scene2d.Actor;
import com.badlogic.gdx.scenes.scene2d.InputEvent;
import com.badlogic.gdx.scenes.scene2d.Stage;
import com.badlogic.gdx.scenes.scene2d.ui.*;
import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener;
import com.badlogic.gdx.scenes.scene2d.utils.ClickListener;
import com.badlogic.gdx.utils.Align;
import com.badlogic.gdx.utils.ScreenUtils;
import com.badlogic.gdx.utils.viewport.FitViewport;
import com.goldsprite.infinityworld.assets.GlobalAssets;
import com.goldsprite.projecttemplategenerator.test.YamlStorage;
import com.goldsprite.projecttemplategenerator.test.YamlUtils;
import com.goldsprite.projecttemplategenerator.testold.HttpFileDownloader;
import com.goldsprite.projecttemplategenerator.testold.PackageNameReplacer;
import com.goldsprite.projecttemplategenerator.testold.ZipFileExtractor;
import org.yaml.snakeyaml.Yaml;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

public class ProjectTemplateGenerator extends ApplicationAdapter {
	private Stage stage;
	private Table mainTable;
	private Label consoleArea;
	private Map<String, Object> templateConfigData;
	private Skin skin;
	private final String skinPath = "ui_skins/shade/skin/uiskin.json";
	private FitViewport viewport;

	public String defaultTemplateConfigPath = "resources/template-config.yaml";
	public String usrTemplateConfigPath = "build/template-config.yaml";
	private ScrollPane consoleAreaScrollPane;
	private YamlUIBuilder yamlBuilder;
	private Label.LabelStyle localLabelStyle;
	private TextButton.TextButtonStyle localTextBtnStyle;

	private ConcurrentLinkedQueue<Runnable> logTasks = new ConcurrentLinkedQueue<>();
	private ConcurrentLinkedQueue<Runnable> runTasks = new ConcurrentLinkedQueue<>();
	public static boolean apply;

	public String defaultApplicationDataPath = "resources/application-data.yaml";
	public String usrApplicationDataPath = "build/application-data.yaml";
	public Map<String, Object> appConfigData = new LinkedHashMap<>();
	private SelectBox<String> mirrorSelect;

	public String curMirror() {
		return mirrorSelect.getSelected();
	}

	private boolean newVersionDetected, hasNewVersion, newVersionDownloading;
	private String latest_version = "";
	private String newVersionLink = "";
	private File newVersionApkFile;

	//创建
	@Override
	public void create() {

		new GlobalAssets();
		skin = GlobalAssets.getInstance().editorSkin;

		localLabelStyle = new Label.LabelStyle(skin.get(Label.LabelStyle.class));
		localLabelStyle.font = GlobalAssets.getInstance().editorFont;
		skin.get(Label.LabelStyle.class).font = localLabelStyle.font;

		localTextBtnStyle = new TextButton.TextButtonStyle(skin.get(TextButton.TextButtonStyle.class));
		localTextBtnStyle.font = GlobalAssets.getInstance().editorFont;
		skin.get(TextButton.TextButtonStyle.class).font = localTextBtnStyle.font;

		viewport = new FitViewport(960f, 540);
		viewport.apply(true);


		stage = new Stage(viewport);
		Gdx.input.setInputProcessor(stage);


		//创建默认配置文件
		if (!YamlStorage.exists(usrTemplateConfigPath)) {
			//复制defaultYamlOptionsPath文件到usrYamlOptionsPath
			FileUtils.copyFile(defaultTemplateConfigPath, usrTemplateConfigPath);
		}
		//创建默认镜像配置文件
		if (!YamlStorage.exists(usrApplicationDataPath)) {
			//复制defaultYamlOptionsPath文件到usrYamlOptionsPath
			FileUtils.copyFile(defaultApplicationDataPath, usrApplicationDataPath);
		}

		mainTable = new Table();
		mainTable.setFillParent(true);

		// 模拟控制台信息区域
		consoleArea = new Label("控制台输出...\n", localLabelStyle);
		consoleArea.setAlignment(Align.topLeft);
		consoleAreaScrollPane = new ScrollPane(consoleArea, skin);
		consoleAreaScrollPane.setFadeScrollBars(false);

		//菜单栏
		Table menuTable = new Table(skin);

		//当前版本号
		TextButton curVersionLabel = new TextButton("V"+Version.VERSION, localTextBtnStyle);
		curVersionLabel.setDisabled(true);
		menuTable.add(curVersionLabel).space(2);

		// 更新按钮
		TextButton updateBtn = new TextButton("检查更新", localTextBtnStyle);
		updateBtn.addListener(new ClickListener() {
				public void clicked(InputEvent event, float x, float y) {
					if(newVersionDownloading){
						logToConsoleTask("坏家伙，坏家伙！");
						return;
					}
					if (!newVersionDetected) {
						newVersionDownloading = true;
						logToConsoleTask("开始检测...");
						new Thread(()->{
							try {
								String link = (String) appConfigData.get("update-check-link");
								link = getAppFormatString(link);
								String rawContent = readFileStringFromRemoteZip(link, "project-template-generator.yaml");
								logToConsoleTask("云端url: " + link);
								logToConsoleTask("云端版本数据: \n" + rawContent);
								Yaml yaml = new Yaml();
								Map<String, Object> data = yaml.load(rawContent);
								latest_version = (String) data.get("latest-version");
								logToConsoleTask("云端版本号: " + latest_version);
								hasNewVersion = Version.hasNew(latest_version);
								newVersionLink = (String) data.get("download-link");
								newVersionLink = getAppFormatString(newVersionLink);
								newVersionDetected = true;
								newVersionDownloading = false;
								addAsyncTask(()->updateVersion());
							} catch (Exception e) {
								logToConsoleTask("执行异常: " + getStackTraceStr(e));
							}
						}).start();
					}
					else{
						updateVersion();
					}
				}
			});
		menuTable.add(updateBtn).space(5);

		//读取app配置(镜像源)列表
		appConfigData = YamlStorage.loadOrCreateYaml(usrApplicationDataPath, appConfigData);
		//添加镜像选择菜单
		TextButton mirrorSelectLabel = new TextButton("镜像选择", localTextBtnStyle);
		mirrorSelectLabel.setDisabled(true);
		menuTable.add(mirrorSelectLabel).space(5);
		mirrorSelect = new SelectBox<>(skin);
		ArrayList<String> items = (ArrayList<String>) appConfigData.get("mirror-links");
		mirrorSelect.setItems(items.toArray(new String[]{}));
		mirrorSelect.setSelectedIndex((int) appConfigData.get("mirror-select"));
		mirrorSelect.addListener(new ChangeListener() {
				public void changed(ChangeListener.ChangeEvent ev, Actor a) {
					appConfigData.put("mirror-select", (int) mirrorSelect.getSelectedIndex());
					logToConsole("镜像选择到: " + curMirror());
				}
			});
		logToConsole("读取镜像源列表成功.");
		menuTable.add(mirrorSelect).expand().fill();

		mainTable.add(menuTable).expandX().fillX().row();

		// 动态创建参数填写清单界面
		Table formTable = new Table(skin);
		formTable.defaults().pad(10);

		// 加载 YAML 配置
		templateConfigData = YamlStorage.loadOrCreateYaml(usrTemplateConfigPath, new LinkedHashMap<>());
		//根据yaml数据动态生成布局
		yamlBuilder = new YamlUIBuilder(skin);
		Table dynamicTable = yamlBuilder.buildLayout(templateConfigData);
		formTable.add(dynamicTable).expandX().fillX().row();
		//空行占位(防止手机屏幕看不见内容)
		int emptyLine = 20;
		formTable.add(new String(new char[emptyLine]).replace('\0', '\n'));

		ScrollPane scrollPane = new ScrollPane(formTable, skin);
		scrollPane.setFlickScroll(false);
		scrollPane.setFadeScrollBars(false);
		scrollPane.setScrollingDisabled(false, false);


		// 复制按钮
		TextButton copyButton = new TextButton("Copy Log", skin);
		copyButton.addListener(new ClickListener() {
				public void clicked(InputEvent event, float x, float y) {
					String log = consoleArea.getText().toString();
					Gdx.app.getClipboard().setContents(log);
				}
			});
		// 应用按钮
		TextButton applyButton = new TextButton("Apply", skin);
		applyButton.addListener(new ClickListener() {
				public void clicked(InputEvent event, float x, float y) {
					apply = true;
					saveYamlConfig(dynamicTable);
					logToConsole("配置已保存!");
					YamlStorage.saveYaml(appConfigData, usrApplicationDataPath);
					logToConsole("镜像选择已保存!");
				}
			});
		// 开始按钮
		TextButton startButton = new TextButton("生成(使用镜像)", localTextBtnStyle);
		startButton.addListener(new ClickListener() {
				public void clicked(InputEvent event, float x, float y) {
					if (!apply) {
						logToConsole("请确认Apply应用后再开始生成.");
						return;
					}
					else apply = false;
					logToConsole("Starting project generation...");
					// 执行逻辑
					generateProject(templateConfigData, curMirror());
					//logToConsole("Project generation completed!");
				}
			});

		// 布局清单列表和控制台
		//mainTable.add(scrollPane).expandX().fillX().row();
		//mainTable.add(consoleAreaScrollPane).growX().height(150).pad(0).row();
		SplitPane splitPane = new SplitPane(scrollPane, consoleAreaScrollPane, false, skin);
		mainTable.add(splitPane).expandX().fillX().row();

		// 按钮区域
		Table buttonTable = new Table();
		buttonTable.add(copyButton).pad(5);
		buttonTable.add(applyButton).pad(5);
		buttonTable.add(startButton).pad(5);
		mainTable.add(buttonTable).pad(10);

		stage.addActor(mainTable);
	}

	@Override
	public void render() {
		ScreenUtils.clear(Color.DARK_GRAY);

		executeLogTasks();
		executeRunTasks();

		stage.act();
		stage.draw();
	}

	@Override
	public void resize(int width, int height) {
		viewport.update(width, height, true);
	}

	@Override
	public void dispose() {
		stage.dispose();
	}


	//更新新版本
	public void updateVersion() {
		if (hasNewVersion) {
			String content = "检测到新版本: " + latest_version;
			content += "\n" + "是否更新?";
			Label contentLabel = new Label(content, localLabelStyle);
			Dialog dialog = new Dialog("New Version!", skin);
			TextButton positiveBtn = new TextButton("Yes", localTextBtnStyle);
			TextButton cancelBtn = new TextButton("No", localTextBtnStyle);
			dialog.text(contentLabel).button(positiveBtn).button(cancelBtn);
			dialog.show(stage);

			positiveBtn.addListener(new ClickListener() {
					public void clicked(InputEvent ev, float x, float y) {
						dialog.cancel();
						installNewVersion();
					}
				});
		}
		else {
			logToConsoleTask("无新版本");
		}

	}

	public void installNewVersion() {
		newVersionDownloading = true;
		new Thread(() -> {
			try {
				String destDir = getAppFormatString("build/${release-type}");
				String realOutputDir = Gdx.files.local(destDir).file().getAbsolutePath();
				if (newVersionApkFile == null) {
					//下载到本地
					logToConsoleTask("latest-version: " + latest_version + ", 开始下载: " + newVersionLink);
					newVersionApkFile = progressDownload(newVersionLink, realOutputDir, 512);
				}
				newVersionDownloading = false;
				if (Gdx.app.getType().equals(Application.ApplicationType.Android))
					Platform.androidApi.installApk(newVersionApkFile);
				else if (Gdx.app.getType().equals(Application.ApplicationType.Desktop)) {
					logToConsoleTask("新版本程序已下载到目标位置: " + realOutputDir);
				}
			} catch (Exception e) {
				logToConsoleTask("执行异常: " + getStackTraceStr(e));
			}
		}).start();
	}


	private void saveYamlConfig(WidgetGroup formTable) {
		yamlBuilder.collectConfigData(formTable, templateConfigData);
		try {
			YamlStorage.saveYaml(templateConfigData, usrTemplateConfigPath);
		} catch (Exception e) {
			e.printStackTrace();
			logToConsole("Error saving configuration!");
		}
	}

	public void generateProject(Map<String, Object> configData, String curMirror) {
		new Thread(() -> {
			try {
				// 加载 YAML 配置
				String downloadUrl = YamlUtils.getNestedVal(configData, "download-url", String.class);
				downloadUrl = getAppFormatString(downloadUrl);
				logToConsoleTask("使用链接下载: " + downloadUrl);
				String outputDirectory = YamlUtils.getNestedVal(configData, "output-directory", String.class);
				String oldProjectName = YamlUtils.getNestedVal(configData, "project.project-name.old", String.class);
				String newProjectName = YamlUtils.getNestedVal(configData, "project.project-name.new", String.class);
				String oldPackageName = YamlUtils.getNestedVal(configData, "project.package-name.old", String.class);
				String newPackageName = YamlUtils.getNestedVal(configData, "project.package-name.new", String.class);

				File outputDir = Gdx.files.local(outputDirectory + "/" + newProjectName + "/" + oldProjectName + ".zip").file();
				String realOutputDir = outputDir.getAbsolutePath();
				String destDirectory = outputDir.getParentFile().getAbsolutePath();

				// 下载模板 ZIP
				logToConsoleTask("destDirectory: " + destDirectory);
				logToConsoleTask("realOutputDir: " + realOutputDir);
				File zipFile = progressDownload(downloadUrl, realOutputDir, 512);


				// 解压模板到指定目录
				File destDirectoryFile = new File(destDirectory);
				ZipFileExtractor.unzip(zipFile, destDirectory);
				logToConsoleTask("unzip解压步骤成功");

				// 替换包名
				PackageNameReplacer.replacePackageNames(destDirectoryFile, oldPackageName, newPackageName);
				logToConsoleTask("批量应用包名完成");

				//替换文件项目名
				PackageNameReplacer.replaceProjectNames(destDirectoryFile, oldProjectName, newProjectName);
				// 替换内容项目名
				PackageNameReplacer.replaceStrings(destDirectoryFile, oldProjectName, newProjectName);
				//替换顶层目录名
				{
					File newFile = new File(destDirectoryFile, newProjectName);
					File[] listFiles = destDirectoryFile.listFiles(File::isDirectory);
					if (listFiles != null) {
						listFiles[0].renameTo(newFile);
					}
					else logToConsoleTask("顶层项目名替换失败.");
				}
				logToConsoleTask("批量应用项目名完成");

				String str = "项目生成成功，目录: " + destDirectory;
				System.out.println(str);
				logToConsoleTask(str);
			} catch (Exception e) {
				//e.printStackTrace();
				logToConsoleTask("执行生成异常: " + getStackTraceStr(e));
				//throw new RuntimeException("生成项目失败: "+e);
			}
		}).start();
	}

	private File progressDownload(String downloadUrl, String realOutputDir, int intervalKb) throws IOException {
		File file = HttpFileDownloader.downloadFile(downloadUrl, realOutputDir, intervalKb, (downloadedKb, totalKb) -> {
			logToConsoleTask(
				String.format(
					"下载进度(%.2f%%): %.2f/%.2f MB",
					100f * downloadedKb / totalKb,
					downloadedKb / 1024.0,
					totalKb / 1024.0));
		});
		logToConsoleTask("文件下载成功");
		return file;
	}

	private String getStackTraceStr(Exception e) {
		StringWriter sw = new StringWriter();
		e.printStackTrace(new PrintWriter(sw));
		return e.getMessage()+"\n"+sw.toString();
	}


	public String getAppFormatString(String rawStr) {
		String projectName = BuildConfig.PROJECT_NAME;
		String projectVersion = latest_version;
		String releaseName = projectName+"_V"+projectVersion;

		Application.ApplicationType type = Gdx.app.getType();
		String releaseType = releaseName+".exe";
		if (type.equals(Application.ApplicationType.Android)) releaseType = releaseName+".apk";

		rawStr = rawStr.replace("${mirror-link}", curMirror());
		rawStr = rawStr.replace("${version}", Version.VERSION);
		rawStr = rawStr.replace("${latest-version}", latest_version);
		rawStr = rawStr.replace("${release-type}", releaseType);
		return rawStr;
	}

	public String getHttpString(String urlStr) {
		String rawContent = "";
		try {
			// 创建 URL 对象
			URL url = new URL(urlStr);

			// 打开 HTTP 连接
			HttpURLConnection connection = (HttpURLConnection) url.openConnection();
			connection.setRequestMethod("GET");

			// 设置 User-Agent 模拟浏览器
			connection.setRequestProperty("User-Agent", "Mozilla/5.0");

			// 检查响应码
			int responseCode = connection.getResponseCode();
			//if (responseCode == 200) { // 200 表示成功
			// 读取文件内容
			try (BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()))) {
				StringBuilder content = new StringBuilder();
				String line;
				while ((line = reader.readLine()) != null) {
					content.append(line).append("\n");
				}
				System.out.println("File Content:\n" + content);
				rawContent = content.toString();
			}
            /*} else {
			 System.out.println("Failed to fetch content. Response code: " + responseCode);
			 }*/
		} catch (Exception e) {
			//e.printStackTrace();
			logToConsoleTask("获取httpString失败: " + getStackTraceStr(e));

		}
		return rawContent;
	}

	/**
	 * 从远程 ZIP 文件中读取指定文件内容。
	 *
	 * @param urlStr         ZIP 文件的 URL
	 * @param targetFileName 目标文件名
	 * @return 目标文件内容（String），如果未找到则返回 null
	 * @throws Exception 如果发生网络或文件处理错误
	 */
	public String readFileStringFromRemoteZip(String urlStr, String targetFileName) throws Exception {
		StringBuilder content = new StringBuilder();

		try{
		// 打开 URL 连接
		URL url = new URL(urlStr);
		HttpURLConnection connection = (HttpURLConnection) url.openConnection();
		connection.setRequestMethod("GET");
		// 设置连接和读取超时
		connection.setConnectTimeout(10000); // 10秒连接超时
		connection.setReadTimeout(15000);    // 15秒读取超时

		// 检查响应代码
		if (connection.getResponseCode() == HttpURLConnection.HTTP_OK) {
			try (InputStream inputStream = connection.getInputStream();
			ZipInputStream zipStream = new ZipInputStream(inputStream, Charset.forName("UTF-8"))) {

				ZipEntry entry;
				while ((entry = zipStream.getNextEntry()) != null) {
					if (entry.getName().endsWith(targetFileName)) {
						// 读取目标文件内容
						try (BufferedReader reader = new BufferedReader(new InputStreamReader(zipStream))) {
							String line;
							while ((line = reader.readLine()) != null) {
								content.append(line).append("\n");
							}
						}
						return content.toString();
					}
				}
			}
		}
		else {
			logToConsoleTask("Failed to fetch ZIP file. HTTP code: " + connection.getResponseCode());
		}
		}catch(Exception e){
			logToConsoleTask("执行异常: "+getStackTraceStr(e));
		}
		return null; // 未找到目标文件
	}

	private void logToConsole(String message) {
		consoleArea.setText(consoleArea.getText() + message + "\n");
		consoleAreaScrollPane.scrollTo(0, 0, 0, 0);
	}

	// 封装日志任务方法
	public void logToConsoleTask(String message) {
		// 将任务加入队列
		logTasks.add(() -> {
			logToConsole(message);
		});
	}

	// 在 render 方法中调用，执行所有任务
	public void executeLogTasks() {
		Runnable task;
		while ((task = logTasks.poll()) != null) {
			task.run();
		}
	}

	public void addAsyncTask(Runnable run){
		runTasks.add(run);
	}
	public void executeRunTasks() {
		Runnable task;
		while ((task = runTasks.poll()) != null) {
			task.run();
		}
	}
}

